//
//  ViewController.m
//  TestDispatch
//
//  Created by shaowei on 13-7-20.
//  Copyright (c) 2013年 shaowei. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - dispatch

/*
 * dispatch_async : 异步执行，意思就是，把参数里的block添加到queue后，函数就马上返回，继续执行下面的语句（不论该block是否执行完成。）
 * dispatch_sync : 同步执行，要把参数里的block添加到queue，要等待block执行完毕，函数才能返回执行下面的语句，否则，该线程就阻塞（卡死）在这条语句上（就像执行了sleep()一样）。所以，特别是在主线程上使用该方法要特别注意，block要执行很长时间的话，主线程就阻塞了。在其他线程也要注意，任何一个线程被阻塞都是很严重的问题。
 */

//创建队列

- (void)create_queue{
    /*
     *dispatch_queue_create(<#const char *label#>, <#dispatch_queue_attr_t attr#>)
     *第一个参数是c字符串，就是该标识队列的唯一id，同一app内尽量不要重复。
     *参数2，是标识创建queue的类型，null：串行，DISPATCH_QUEUE_CONCURRENT：并行
     */

    dispatch_queue_t serialQueue = dispatch_queue_create("com.test.firstqueue", NULL);//串行队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.test.firstqueue", DISPATCH_QUEUE_CONCURRENT);//并行队列
    
    /*
     *凡是带有create的接口创建的变量，都要释放release
     *既然有release接口，当然就要有retain接口
     */
    
    dispatch_retain(serialQueue);
    dispatch_release(serialQueue);
    
    dispatch_release(serialQueue);
    dispatch_release(concurrentQueue);
    
    
}

//系统提供的标准queue
- (void)systemQueue{
    //Main dispatch queue 主线程的队列，属于串行
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    /*
     *Global dispatch queue  子线程队列 ,属于并行队列
     *参数1：队列的优先级，主要分为4个等级，常用的就是默认等级 即可
     
     #define DISPATCH_QUEUE_PRIORITY_HIGH 2
     #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
     #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
     #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
     
     *参数2：系统保留参数，暂时无用，置0即可。
     
     */
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //注意：对这两个线程执行 retain，release 不会有任何效果。
}

// 设置队列的优先级

/*
 * 队列的优先级 与 队列的类型（并行、串行）无关
 * 注意：不可以对上面两个系统提供的queue 设置优先级，否则会产生不可预测的结果
 * 我们一般只对自己create的queue设置优先级
 
 * create生成的队列 都与global queue的默认级别相同。
 */

- (void)setQueueLevel{
    dispatch_queue_t subSerialQueue = dispatch_queue_create("com.test.setlevel", NULL);
    
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //设置第一个参数queue 与 第2个参数queue的优先级相同。注意，第一个queue ，不可以是系统提供的queue。
    dispatch_set_target_queue(subSerialQueue, globalQueue);
    
    /*
     * 小窍门：
     * 有多个串行队列，这些队列之间内部执行是按照串行，但是queue之间是并行，
     * 将这多个串行队列 的优先级 全都设置为 同一个串行队列，那么这个queue之间也就变成串行执行的，以为他们属于同一优先级，没法并行。
     */
    
}

// dispatch_after
- (void)dispatchAfter{
    //在指定的时间后执行，即延迟**的时间执行
    
    /*
     * 代表当前时间延迟3秒后的时间
     * DISPATCH_TIME_NOW 代表当前时间
     * 3ull*NSEC_PER_SEC ull为单位，整个式子表示3秒，感兴趣的可以仔细研究。
     */
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC);
    
    /*
     * 3秒后，在主线程 执行block。
     */
    dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){
        NSLog(@"SW - dispatch_after");
    });
    
    //也可指定绝对时间执行，即指定某年某月某时执行
    //在1970 年后的1024*1024秒后 的那个时间点执行
    dispatch_time_t confirmTime = [self getDispatchTimeByDate:[NSDate dateWithTimeIntervalSince1970:(1024*1024)]];

    dispatch_after(confirmTime, dispatch_get_main_queue(), ^(void){
        NSLog(@"SW -dispatch_after confirmTime");
    });
    
}

// 取得dispatch_time_t格式的绝对时间点
- (dispatch_time_t)getDispatchTimeByDate:(NSDate *)date{
    NSTimeInterval interval;
    double second,subSecond;
    struct timespec time;
    dispatch_time_t milestone;
    
    interval = [date timeIntervalSince1970];
    subSecond = modf(interval, &second);
    time.tv_sec = second;
    time.tv_nsec = subSecond *NSEC_PER_SEC;
    milestone = dispatch_walltime(&time, 0);
    
    return milestone;
}

/*
 * 在你需要将一组block 执行之后，再追加一个结束处理的block。
 * 在serial queue实现很简单，只需要把“结束block”添加的队列的最后即可。
 * 但是在concurrent queue里面就很那实现，因为你无法确定什么时候所有的block执行完，这时就需要 dispatch_group
 */

- (void)dispatchGroupNotify{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_t group = dispatch_group_create();//注意create出来的group，要release
    
    //下面的添加的操作可以 不 在同一个queue内。
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_1");});
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_2");});
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_3");});
    
    //当 添加到组group的所有block完成，那么在主线程调用该block输出。
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"group_finish");});
    
    
    dispatch_release(group);
}

- (void)dispatchGroupWaitForever{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_t group = dispatch_group_create();//注意create出来的group，要release
    
    //下面的添加的操作可以 不 在同一个queue内。
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_1");});
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_2");});
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_3");});
    
    /*
     * 线程阻塞在此，一直等到超时或者group全部执行完毕，函数才返回，继续执行下面的语句
     * DISPATCH_TIME_FOREVER 永久等待，所以这里不会出现因为超时函数才返回的情况
     */
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_release(group);
    
    
    
    
}

- (void)dispatchGroupWaitPartTime{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_t group = dispatch_group_create();//注意create出来的group，要release
    
    //下面的添加的操作可以 不 在同一个queue内。
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_1");});
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_2");});
    dispatch_group_async(group, queue, ^{ NSLog(@"outPrint_3");});
    
    /*
     * 线程阻塞在此，一直等到超时或者group全部执行完毕，函数才返回，继续执行下面的语句
     * waitTime 等待的最长时间，等待时间超过此值，函数会因超时而返回。
     * resultCode 不为0，则意味着超时；为0，则是因为group执行完函数才返回的。
     */
    
    dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, 2ull*NSEC_PER_SEC);
    long resultCode = dispatch_group_wait(group, waitTime);
    dispatch_release(group);
}

#pragma mark -test


- (void)test5{
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        NSLog(@"SW - asyn-1");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"SW - asyn-2");
//        dispatch_sync(queue, ^{
//            NSLog(@"SW - asyn-syn-2");
//        });
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"SW - syn-3");
    });
}

- (void)test4{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//    dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"SW - 11-start");
        for (int i = 0; i< 10000; i++) {
            int j = i;
            j++;
        }
        NSLog(@"SW - 11-end");
    });
    
    dispatch_barrier_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
        NSLog(@"SW - barry-start");
        for (int i = 0; i< 10000; i++) {
            int j = i;
            j++;
        }
        NSLog(@"SW - barry_finish");
    });

    NSLog(@"SW - barry_after");
    
    dispatch_async(queue, ^{
        NSLog(@"SW - 2");
 
    });
    
    dispatch_async(queue, ^{
        NSLog(@"SW - 3");
        
    });
    
    dispatch_release(queue);
    
    
}


- (void)test2{
//    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC)
}


- (void)test1{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i< 10000; i++) {
            int j = i;
        }
        NSLog(@"SW - group_first");
        
    });
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i< 10000; i++) {
            int j = i;
        }
        NSLog(@"SW - group_second");
        
    });
    NSLog(@"SW - assert_after_2");
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i< 10000; i++) {
            int j = i;
        }
        NSLog(@"SW - group_third");
        
    });
    NSLog(@"SW - assert_after_3");
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"SW - group_finish");
    });
    
    NSLog(@"SW - assert_after_notify");
    
    
    dispatch_release(group);
    
    NSLog(@"SW - assert_after_release");
}

- (void)test3{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_sync( queue, ^{
        for (int i = 0; i< 10000; i++) {
            int j = i;
        }
        NSLog(@"SW - group_first");
        
    });
    dispatch_sync( queue, ^{
        for (int i = 0; i< 10000; i++) {
            int j = i;
        }
        NSLog(@"SW - group_second");
        
    });
    NSLog(@"SW - assert_after_2");
    dispatch_sync(queue, ^{
        for (int i = 0; i< 10000; i++) {
            int j = i;
        }
        NSLog(@"SW - group_third");
        
    });
    NSLog(@"SW - assert_after_3");
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"SW - group_finish");
    });
    
    NSLog(@"SW - assert_after_notify");
    
    
    dispatch_release(group);
    
    NSLog(@"SW - assert_after_release");
}

@end
